package com.juc.kill;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @Author HK
 * @Date 2022/5/28 15:48
 * @Version 1.0
 * Desc：线程间通信和合并
 */
public class KillDemo {

    /**
     * 启动10个线程
     * 库存6个
     * 生成一个合并队列
     * 每个用户能拿到自己的请求响应
     */
    public static void main(String[] args) throws InterruptedException {

        ExecutorService executorService = Executors.newCachedThreadPool();
        KillDemo killDemo = new KillDemo();
        killDemo.mergeJob();
        Thread.sleep(2000);

        List<Future<Result>> futureList = new ArrayList<>();
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
            final Long orderId = i + 100L;
            final Long userId = Long.valueOf(i);
            Future<Result> future = executorService.submit(() -> {
                countDownLatch.countDown();
                return killDemo.operate(new UserRequest(orderId, userId, 1));
            });
            futureList.add(future);
        }

        futureList.forEach(future ->{
            try {
                Result result = future.get(300, TimeUnit.MILLISECONDS);
                System.out.println(Thread.currentThread().getName()+":客户端请求响应："+ result);
            }catch (Exception e){
                e.printStackTrace();
            }
        });
        countDownLatch.await();
    }

    //模拟数据库行，设置库存数量
    private Integer stock = 8;

    private BlockingQueue<RequestPromise> queue = new LinkedBlockingQueue<>(10);
    /**
     * 用户库存扣减
     * @param userRequest
     * @return
     */
    public Result operate(UserRequest userRequest) throws InterruptedException {
        // TODO: 2022/5/28 阈值判断
        // TODO: 2022/5/28 队列创建
        RequestPromise requestPromise = new RequestPromise(userRequest);
        boolean enqueueSuccess = queue.offer(requestPromise, 100, TimeUnit.MILLISECONDS);
        if (!enqueueSuccess){
            return new Result(false, "系统繁忙");
        }
        //获取锁
        synchronized (requestPromise){
            try {
                //释放锁
                requestPromise.wait(200);
            } catch (InterruptedException e) {
                return new Result(false, "等待超时");
            }
        }
        return requestPromise.getResult();
    }

    /**
     * 定义一个定时任务
     */
    public void mergeJob(){
        new Thread(() ->{
            ArrayList<RequestPromise> list = new ArrayList<>();
            while (true){
                if (queue.isEmpty()){
                    try {
                        Thread.sleep(10);
                        continue;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //将用户线程批量拿出来放进list
                while (queue.peek() != null){
                    list.add(queue.poll());
                }

                System.out.println(Thread.currentThread().getName()+"：合并扣减库存："+list);

                int sum = list.stream().mapToInt(e -> e.getUserRequest().getCount()).sum();
                //两种情况
                if (sum <= stock){
                    stock -= sum;
                    //notify user
                    list.forEach(requestPromise -> {
                        requestPromise.setResult(new Result(true,"ok"));
                        synchronized (requestPromise){
                            //通知
                            requestPromise.notify();
                        }
                    });
                    continue;
                }
                for (RequestPromise requestPromise : list) {
                    int count = requestPromise.getUserRequest().getCount();
                    if (count <= stock){
                        stock -= count;
                        requestPromise.setResult(new Result(true,"ok"));
                        synchronized (requestPromise){
                            requestPromise.notify();
                        }
                    }else {
                        //
                        requestPromise.setResult(new Result(true,"库存不够了"));
                    }
                }
                list.clear();
            }
        },"mergeThread").start();
    }

}


/**
 * 包含请求和响应对象
 */
class RequestPromise{
    private UserRequest userRequest;
    private Result result;


    public RequestPromise(UserRequest userRequest) {
        this.userRequest = userRequest;
    }

    public RequestPromise(UserRequest userRequest, Result result) {
        this.userRequest = userRequest;
        this.result = result;
    }

    public UserRequest getUserRequest() {
        return userRequest;
    }

    public void setUserRequest(UserRequest userRequest) {
        this.userRequest = userRequest;
    }

    public Result getResult() {
        return result;
    }

    public void setResult(Result result) {
        this.result = result;
    }

    @Override
    public String toString() {
        return "RequestPromise{" +
                "userRequest=" + userRequest +
                ", result=" + result +
                '}';
    }
}

class Result{
    private Boolean success;
    private String msg;

    public Result(Boolean success, String msg) {
        this.success = success;
        this.msg = msg;
    }

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "Result{" +
                "success=" + success +
                ", msg='" + msg + '\'' +
                '}';
    }
}

class UserRequest{
    private Long orderId;
    private Long userId;
    private Integer count;

    public UserRequest(Long orderId, Long userId, Integer count) {
        this.orderId = orderId;
        this.userId = userId;
        this.count = count;
    }

    public Long getOrderId() {
        return orderId;
    }

    public void setOrderId(Long orderId) {
        this.orderId = orderId;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }

    @Override
    public String toString() {
        return "UserRequest{" +
                "orderId=" + orderId +
                ", userId=" + userId +
                ", count=" + count +
                '}';
    }
}
